{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "1cfc195a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "apple 的哈希: 3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b\n",
      "apples 的哈希: f5903f51e341a783e69ffc2d9b335048716f5f040a782a2764cd4e728b0f74d9\n",
      "zpple 的哈希: 2d198bd02ab5e8a7260f50db5dea5672c03151c3febcf3d2ec129263d4f299bd\n"
     ]
    }
   ],
   "source": [
    "# Hash function : sha256\n",
    "from hashlib import sha256\n",
    "\n",
    "def get_hash(message_string):\n",
    "    return sha256(message_string.encode('utf-8')).hexdigest()\n",
    "\n",
    "print(\"apple 的哈希:\", get_hash(\"apple\"))\n",
    "print(\"apples 的哈希:\", get_hash(\"apples\"))\n",
    "print(\"zpple 的哈希:\", get_hash(\"zpple\"))\n",
    "\n",
    "# apple 的哈希: 3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b\n",
    "# apples 的哈希: f5903f51e341a783e69ffc2d9b335048716f5f040a782a2764cd4e728b0f74d9\n",
    "# zpple 的哈希: 2d198bd02ab5e8a7260f50db5dea5672c03151c3febcf3d2ec129263d4f299bd\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "a54a4b03",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Point on secp256k1 curve: (75672206050705717597513752332592681441562708170391675094677140490692301502235, 2079954378639550643990441934946533201466680551826647417569849183466717633402)\n"
     ]
    }
   ],
   "source": [
    "# Hash to curve\n",
    "# Try-And-Increment method\n",
    "\n",
    "from hashlib import sha256\n",
    "from py_ecc.secp256k1 import secp256k1\n",
    "\n",
    "def hash_to_curve_try_and_increment(message):\n",
    "    # 计数器\n",
    "    counter = 0\n",
    "    while True:\n",
    "        # 计算 message 和 counter 的 hash\n",
    "        data = message + counter.to_bytes(32, 'big')\n",
    "        hash_digest = sha256(data).digest()\n",
    "\n",
    "        # 从 hash 计算 x 坐标\n",
    "        x = int.from_bytes(hash_digest, 'big') % secp256k1.P\n",
    "\n",
    "        # 尝试通过椭圆曲线方程 y^2 = x^3 + ax + b,计算 y^2\n",
    "        y_squared = (pow(x, 3, secp256k1.P) + secp256k1.A * x + secp256k1.B) % secp256k1.P\n",
    "        \n",
    "        # 计算 y^2 在模 p 下的平方根，如果有的话（对于 secp256k1，p % 4 = 3，可以用这个方法计算）\n",
    "        y = pow(y_squared, (secp256k1.P + 1) // 4, secp256k1.P)\n",
    "\n",
    "        # 如果 y^2 = y_squared，说明 y^2 是二次剩余， (x, y) 是椭圆曲线上的点，返回它\n",
    "        # 如果不是，则 counter 加一，再试一次\n",
    "        if pow(y, 2, secp256k1.P) == y_squared:\n",
    "\n",
    "            # y^2 有两个平方根 y 和 -y，我们利用 hash 的最后一位决定 y 的符号\n",
    "            sign_bit = hash_digest[-1] & 1\n",
    "            if sign_bit == 1:\n",
    "                y = secp256k1.P - y  # Use -y\n",
    "\n",
    "            return (x, y)\n",
    "\n",
    "        counter += 1\n",
    "\n",
    "# 示例\n",
    "message = 'Example message'.encode('utf-8')\n",
    "point_on_curve = hash_to_curve_try_and_increment(message)\n",
    "print(f\"Point on secp256k1 curve: {point_on_curve}\")\n",
    "\n",
    "# 输出\n",
    "# Point on secp256k1 curve: (75672206050705717597513752332592681441562708170391675094677140490692301502235, 2079954378639550643990441934946533201466680551826647417569849183466717633402)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "fd451b19",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "随机数r: 73024396533133913522992000700997978493545300935845156062873113842229351634806\n",
      "Pedersen hash: (61158186220483422500680232915115660637414963516696475985433668859480078549697, 19925636506537717141567615179623096875787300022679479682581994441236159884610)\n"
     ]
    }
   ],
   "source": [
    "from py_ecc.secp256k1 import secp256k1\n",
    "import os\n",
    "\n",
    "def pedersen_hash(G, P, m, r):\n",
    "    \"\"\"\n",
    "    利用 secp256k1 上的两个点 G 和 P 计算 Pedersen hash\n",
    "    :param G: secp256k1 生成点\n",
    "    :param P: 通过 hash-to-curve 生成的点\n",
    "    :param m: 消息\n",
    "    :param r: 随机数\n",
    "    :return: The Pedersen hash as a point on the secp256k1 curve.\n",
    "    \"\"\"\n",
    "    hash_point = secp256k1.add(secp256k1.multiply(G, m), secp256k1.multiply(P, r))\n",
    "    return hash_point\n",
    "\n",
    "def message_to_int(message):\n",
    "    \"\"\"将消息转换为int\"\"\"\n",
    "    message_hash = sha256(message.encode('utf-8')).digest()\n",
    "    return int.from_bytes(message_hash, 'big')\n",
    "\n",
    "# 示例\n",
    "G = secp256k1.G\n",
    "P = (75672206050705717597513752332592681441562708170391675094677140490692301502235, 2079954378639550643990441934946533201466680551826647417569849183466717633402)\n",
    "m = message_to_int('Example message')\n",
    "r = int.from_bytes(os.urandom(32), 'big') % secp256k1.N  # Random blinding factor\n",
    "print(f\"随机数r: {r}\")\n",
    "# 随机数r: 73024396533133913522992000700997978493545300935845156062873113842229351634806\n",
    "\n",
    "hash_point = pedersen_hash(G, P, m, r)\n",
    "print(f\"Pedersen hash: {hash_point}\")\n",
    "# Pedersen hash: (61158186220483422500680232915115660637414963516696475985433668859480078549697, 19925636506537717141567615179623096875787300022679479682581994441236159884610)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "22553cbd",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
